package de.tuhh.simsearch.model.persistence.contentmgmt.entities;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.ManyToMany;

/**
 * The category entity represents a content category in the database as a database table. A category entity has a
 * category name and a content id, which represents the type of the content, (see {@link Constants}). Category name and id act
 * as primary keys in the database for the category entity table The category entity also holds a list of files that are
 * associated with this category. In the database this is represented by a join table.
 * 
 * @author SimSearch 1
 * @see Constants
 */
@Entity
@IdClass(CategoryEntityId.class)
public class CategoryEntity implements Serializable {

  private static final long serialVersionUID = 1L;

  @Id private Integer contentID;
  @Id private String categoryName;

  @ManyToMany(mappedBy = "categories", cascade = CascadeType.PERSIST) private Set<FileEntity> files = new HashSet<FileEntity>();

  /**
   * The class constructor. This constructor should not be used.
   */
  protected CategoryEntity() {

  }

  /**
   * The class constructor. Sets the content id and the category name of the entity.
   * 
   * @param contentID
   *          the content type
   * @param categoryName
   *          the category name
   */
  public CategoryEntity(Integer contentID, String categoryName) {

    setCategoryName(categoryName);
    setContentID(contentID);

  }

  /**
   * Gets the content id of this category entity
   * 
   * @return the content id
   */
  public Integer getContentID() {

    return contentID;
  }

  /**
   * Sets the content id of this category entity
   * 
   * @param contentID
   *          the content id to setS
   */
  public void setContentID(Integer contentID) {

    this.contentID = contentID;
  }

  /**
   * Gets the category name of this category entity
   * 
   * @return the preference
   */
  public String getCategoryName() {

    return categoryName;
  }

  /**
   * Sets the category name for this category entity.
   * 
   * @param categoryName
   *          the category name
   */
  public void setCategoryName(String categoryName) {

    this.categoryName = categoryName;
  }

  /**
   * Gets the set of files associated with this category. This set is unmodifiable! If the set should be changed, use
   * addFile and removeFile on this entity.
   * 
   * @return the set of files associated with this category
   */
  public Set<FileEntity> getFiles() {

    return Collections.unmodifiableSet(files);
  }

  protected void setFiles(Set<FileEntity> files) {

    this.files = files;

  }

  /**
   * Adds a file to the set of associated files from this category entity
   * 
   * @param f
   *          the file entity to add
   */
  public void addFile(FileEntity f) {

    this.files.add(f);
    if (!(f.getCategories().contains(this))) {

      f.addCategory(this);
    }
  }

  /**
   * Removes a file from the set of associated files of this category entity
   * 
   * @param f
   *          the file to be removed
   */
  public void removeFile(FileEntity f) {

    this.files.remove(f);
    if (f.getCategories().contains(this)) {

      f.removeCategory(this);
    }
  }

}


class CategoryEntityId implements Serializable {

  private static final long serialVersionUID = -8401212849923187358L;

  private Integer contentID;
  private String categoryName;

  public CategoryEntityId() {

  }

  /**
   * Sets the category name for this entity
   * 
   * @param category
   *          name the category name to set
   */
  public void setCategoryName(String categoryName) {

    this.categoryName = categoryName;
  }

  /**
   * Gets the category name of this category entity
   * 
   * @return the category name
   */
  public String getCategoryName() {

    return categoryName;
  }

  /**
   * Gets the content id of this category entity
   * 
   * @return the contentID of this category entity
   */
  public Integer getContentID() {

    return contentID;
  }

  /**
   * Sets the content id for this category entity
   * 
   * @param contentID
   *          the contentID to set
   */
  public void setContentID(Integer contentID) {

    this.contentID = contentID;
  }

  @Override
  public int hashCode() {

    return (contentID.toString() + categoryName).hashCode();
  }

  @Override
  public boolean equals(Object obj) {

    boolean retval = false;

    if (obj instanceof CategoryEntityId) {

      CategoryEntityId catID = (CategoryEntityId) obj;
      retval = (catID.getContentID().equals(this.contentID) && categoryName.equals(this.categoryName));
    }

    return retval;
  }

}
